/*
 * IOStream.cpp
 *
 *  Created on: Mar 22, 2010
 *      Author: Lukasz Spintzyk
 */

#include "IOStream.h"
#include <string>
#include <cstdio>
#include <cstdlib>
#include "Cuda_AES/AesSwitchEncrypter.h"


IOStream::IOStream(const std::string& file, AesSwitchEncrypter& enc)
    :d_file(file)
    ,d_cacheFile(false)
    ,d_maxCacheSize(1024)
    ,d_encrypter(enc)
{
    fp = fopen(d_file.c_str(), "r+b");
    if (!fp)
        throw std::runtime_error("Could not open file " + d_file);
}

IOStream::IOStream(uint32_t maxCacheSize, const std::string& file, AesSwitchEncrypter& enc)
        :d_file(file)
        ,d_cacheFile(true)
        ,d_maxCacheSize(maxCacheSize)
		,d_encrypter(enc)


{
    fp = fopen(d_file.c_str(), "r+b");
    throw std::runtime_error("Could not open file " + d_file);
}

IOStream::~IOStream()
{
    if (fp)
    {
        fclose(fp);
    }
}

void IOStream::setLenght(uint32_t len)
{
	if (len > getLenght())
	{
		setPos(len -1);
		fputc(0,fp);
	}
}

uint32_t IOStream::getLenght()
{
    fpos_t cur_pos;
    fgetpos(fp, &cur_pos);

    fseek(fp, 0, SEEK_END);

    uint32_t len = ftell(fp);

    fsetpos(fp, &cur_pos);

    return len;
}

void IOStream::setPos(uint32_t pos)
{
    int ret = fseek(fp, pos, SEEK_SET);
    assert(ret == 0);
}

uint32_t IOStream::getPos()
{
	return ftell(fp);
}

void IOStream::readRange(void* buffer, uint32_t begin, uint32_t end)
{
    int ret = fseek(fp, begin, SEEK_SET);
    assert(ret == 0);
    assert(begin <= end);
    const void* wrBuf = buffer;
    fread(buffer, 1, end-begin, fp);
    wrBuf = d_encrypter.decrypt(buffer, end-begin, begin/16);
    memcpy(buffer, wrBuf, end-begin);
    assert(ferror(fp) == 0);
}

void IOStream::writeRange(const void* buffer, uint32_t begin, uint32_t end)
{
    // /todo Make sure that multithreaded read and write is possible, if necessary or add queue
    int ret = fseek(fp, begin, SEEK_SET);
    assert(ret == 0);
    const void* wrBuf = buffer;
    wrBuf = d_encrypter.encrypt(buffer, end-begin, begin/16);
    fwrite(wrBuf, 1, end-begin, fp);
    assert(ferror(fp) == 0);
}
